/***************************************************************************
 *   Copyright (C) 2009 by maarten,,,   *
 *   maarten@maarten-laptop   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef UTILSMATRIX_H
#define UTILSMATRIX_H

#include <QVector>
#include <QString>

#include <iostream>

using namespace std;

namespace utils {

/**
	@author maarten,,, <maarten@maarten-laptop>
*/
template <typename T>
class Matrix{
public:
    Matrix(int rows, int cols);
    Matrix(int rows, int cols, int type);

    ~Matrix();

    QVector<T>* operator [] (int index) { return m_matrix->at(index); }
//non-const
    const QVector<T>* operator [] (int index) const { return
m_matrix->at(index); } //const

    int rows() const
    {
        return m_rows;
    }

    int cols() const
    {
        return m_cols;
    }
    
    void print(){
        
//         cout << "\n";
//         for(int i = 0; i < m_rows; ++i){
//           cout << "[ ";
//           for(int j = 0; j < m_cols; ++j){
//             cout << *getItem(i,j) << " ";
//           }
//           cout << "]\n";
//         }
//         cin.get(); 
    }

    T getItem(int r, int c){ return (m_matrix->at(r))->at(c); }

    /*
        Only use this when multipliable items...
    */
    Matrix<T>* multiplyWith(Matrix<T> *temp){   
        // asert for cols this = rows temp TODO
        if(temp->rows() != cols())
            qDebug("ASSERTION FAULT: cols != ROWS");

        Matrix<T> *ret = new Matrix(m_rows,temp->cols());
        /*qDebug("Rows: " + QString::number(m_rows).toLatin1() + 
                "Cols: " + QString::number(temp->cols()).toLatin1());*/
        
        for(int i = 0; i < m_rows; ++i){
            for(int j = 0; j < temp->cols(); ++j){
                float newValue = 0;
                float tempF1 = 0,tempF2 = 0;
                
                for(int s = 0; s < m_cols; ++s){
                    /*cout << "Calculating..." << "i=" << i << ",j=" << j <<
",s="
                        << s << endl;*/
                    tempF1 = *(getItem(i,s));
                    //cout << "F1" << tempF1 << endl;
                    tempF2 = *(temp->getItem(s,j));
                    //cout << "F2" << tempF2 << endl;
                    newValue+= tempF1*tempF2;
                }
                ret->setValue(i,j,new float(newValue));
            }
        }
    
        return ret;
    }

    void setValue(int r, int c, T const& val){(*(*m_matrix)[r])[c] = val;}


private:
    int m_rows;
    int m_cols;
    QVector<QVector<T>*> *m_matrix;
};



}

namespace utils {


template <typename T> Matrix<T>::Matrix(int rows, int cols): m_rows(rows),
m_cols(cols)
{
    m_matrix = new QVector<QVector<T>*>;

    for(int i = 0; i < rows; ++i)
        m_matrix->push_back(new QVector<T>(cols));

}

// for floats, add 1 as a par (NOT NICE CODE, to be fixed)
template <typename T>  Matrix<T>::Matrix(int rows, int cols, int type):
m_rows(rows),
m_cols(cols)
{
    m_matrix = new QVector<QVector<T>*>;

    for(int i = 0; i < rows; ++i)
        m_matrix->push_back(new QVector<T>(cols));

    for(int i = 0; i < rows; ++i){
        for(int j = 0; j < cols; ++j){
            setValue(i,j,new float(0));
        }
    }

}

template <typename T> Matrix<T>::~Matrix()
{
    
    for(int i = 0; i < m_matrix->size(); ++i){
        for(int j = 0; j < m_matrix->at(i)->size(); ++j){
            delete m_matrix->at(i)->at(j);
        }
        m_matrix->at(i)->clear();
    }

    m_matrix->clear();
}

}

#endif




